package game.games.rpg.dungeongenerator;

import java.util.Random;

public class DiffusionLimitedAggregation
{

    public static void main(String[] args)
    {
        /* Main Mapping Variables & declarations */
        int width = 80, height = 24, cx = 0, cy = 0;
        // Set the map array
        int[][] map = new int[width][height];
        // Initialize the Map Array to Zeros
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                map[x][y] = 0;
            }
        }
        /* Functional Variables */
        int builderSpawned = 0;
        int builderMoveDirection = 0;
        int allocatedBlocks = 0; // variable used to track the percentage of the
                                 // map filled
        int rootX = width / 2, rootY = height / 2; // this is where the growth starts from.
                                    // Currently center of map
        final int MAX_STEPPED = 10;
        int stepped = 0; // this is how long corridors can be
        boolean orthogonalAllowed = false; // Orthogonal movement allowed? If
                                           // not, it carves a wider cooridor on
                                           // diagonal
        /* The Diffusion Limited Aggregation Loop */
        // quit when an eighth of the map is filled
        while (allocatedBlocks < ((width * height) / 6))
        {
            if (builderSpawned != 1)
            {
                // Spawn at random position
                //cx = (int) (2 + Math.floor(random() * width - 2));
                cx = new Random().nextInt(width);
//                cy = (int) (2 + Math.floor(random() * height - 2));
                cy = new Random().nextInt(height);
                // See if builder is ontop of root
                if (Math.abs(rootX - cx) <= 0 && Math.abs(rootY - cy) <= 0)
                {
                    // builder was spawned too close to root, clear that floor
                    // and respawn
                    if (map[cx][cy] != 1)
                    {
                        map[cx][cy] = 1;
                        allocatedBlocks++;
                    } // end if
                }
                else
                {
                    builderSpawned = 1;
                    builderMoveDirection = (int) Math.floor(random() * 8);
                    stepped = 0;
                } // end if
            }
            else
            { // builder already spawned and knows it's direction, move builder
                /* North */
                if (builderMoveDirection == 0 && cy > 0)
                {
                    cy--;
                    stepped++;
                }
                /* East */
                else if (builderMoveDirection == 1 && cx < width - 1)
                {
                    cx++;
                    stepped++;
                }
                /* South */
                else if (builderMoveDirection == 2 && cy < height - 1)
                {
                    cy++;
                    stepped++;
                }
                /* West */
                else if (builderMoveDirection == 3 && cx > 0)
                {
                    cx++;
                    stepped++;
                }
                /* Northeast */
                else if (builderMoveDirection == 4 && cx < width - 1 && cy > 0)
                {
                    cy--;
                    cx++;
                    stepped++;
                }
                /* Southeast */
                else if (builderMoveDirection == 5 && cx < width - 1 && cy < height - 1)
                {
                    cy++;
                    cx++;
                    stepped++;
                }
                /* Southwest */
                else if (builderMoveDirection == 6 && cx > 0 && cy < height - 1)
                {
                    cy++;
                    cx--;
                    stepped++;
                }
                /* Northwest */
                else if (builderMoveDirection == 7 && cx > 0 && cy > 0)
                {
                    cy--;
                    cx--;
                    stepped++;
                }
                /* ensure that the builder is touching an existing spot */
                if (cx < width - 1 && cy < height - 1 && cx > 1 && cy > 1 && stepped <= MAX_STEPPED)
                {
                    /* East */
                    if (map[cx + 1][cy] == 1)
                    {
                        if (map[cx][cy] != 1)
                        {
                            map[cx][cy] = 1;
                            allocatedBlocks++;
                        }
                    }
                    /* West */
                    else if (map[cx - 1][cy] == 1)
                    {
                        if (map[cx][cy] != 1)
                        {
                            map[cx][cy] = 1;
                            allocatedBlocks++;
                        }
                    }
                    /* South */
                    else if (map[cx][cy + 1] == 1)
                    {
                        if (map[cx][cy] != 1)
                        {
                            map[cx][cy] = 1;
                            allocatedBlocks++;
                        }
                    }
                    /* North */
                    else if (map[cx][cy - 1] == 1)
                    {
                        if (map[cx][cy] != 1)
                        {
                            map[cx][cy] = 1;
                            allocatedBlocks++;
                        }
                    }
                    /* Northeast */
                    else if (map[cx + 1][cy - 1] == 1)
                    {
                        if (map[cx][cy] != 1)
                        {
                            map[cx][cy] = 1;
                            allocatedBlocks++;
                            if (!orthogonalAllowed)
                            {
                                map[cx + 1][cy] = 1;
                                allocatedBlocks++;
                            }
                        }
                    }
                    /* Southeast */
                    else if (map[cx + 1][cy + 1] == 1)
                    {
                        if (map[cx][cy] != 1)
                        {
                            map[cx][cy] = 1;
                            allocatedBlocks++;
                            if (!orthogonalAllowed)
                            {
                                map[cx + 1][cy] = 1;
                                allocatedBlocks++;
                            }
                        }
                    }
                    /* Southwest */
                    else if (map[cx - 1][cy + 1] == 1)
                    {
                        if (map[cx][cy] != 1)
                        {
                            map[cx][cy] = 1;
                            allocatedBlocks++;
                            if (!orthogonalAllowed)
                            {
                                map[cx - 1][cy] = 1;
                                allocatedBlocks++;
                            }
                        }
                    }
                    /* Northwest */
                    else if (map[cx - 1][cy - 1] == 1)
                    {
                        if (map[cx][cy] != 1)
                        {
                            map[cx][cy] = 1;
                            allocatedBlocks++;
                            if (!orthogonalAllowed)
                            {
                                map[cx - 1][cy] = 1;
                                allocatedBlocks++;
                            }
                        }
                    }
                }
                else
                {
                    builderSpawned = 0;
                }
            } // end if
        } // end while
        // print
        for (int y = 0; y < height; y++)
        {
            StringBuilder sb = new StringBuilder();
            for (int x = 0; x < width; x++)
            {
                switch (map[x][y])
                {
                    case 1:
                    {
                        sb.append(' ');
                        break;
                    }
                    case 0:
                    {
                        sb.append('%');
                        break;
                    }
                    default:
                    {
                        sb.append(map[y][x]);
                        break;
                    }
                }
                
            }
            System.out.println(sb.toString());
        }
    }
    
    private static double random()
    {
        return new Random().nextDouble();
    }
}
